package version2;
import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.Timer;
import org.lwjgl.util.glu.GLU;

public class Version2 {

	static double sphererad=0.5;
	
	private static Timer fpsTimer = new Timer();
	private static float lastTimerTick;
	
	private static String title = "VL Computergraphik";
	private static int width = 800, height = 600, depth = 10;
	
	private static int maxFlashes = 0;
	static float bias[]={0,0,0};
	public static Blitz bli[] = new Blitz[7];
	public static Blitz wackelblitz;
	
	public static void main(String[] argv) {
		try {
			Display.setDisplayMode(new DisplayMode(width, height));
			Display.create();
			Display.setTitle(title);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
		
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glLoadIdentity();
		
		GL11.glEnable(GL11.GL_DEPTH_TEST);
		GLU.gluPerspective(50.0f, 1.0f*width/height, 0.1f, 1f*depth);
		GLU.gluLookAt(0, 0, 0, 0, 0, 1, 0, 1, 0);

		GL11.glEnable(GL11.GL_BLEND);
		GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);

		initializeLighting();
		
		// and initialize Lightning!
		
		wackelblitz = new Blitz(3128);
		double startpunkt[] = {0, 0, depth/2};
		double richtung[] = {-1,0,-1};
		double spleisswahrsch = 0.62;
		int laenge = 15;
		double dicke=0.025;
		double geolaenge=0.3;
		

		wackelblitz.sphereradius=sphererad;
		wackelblitz.preset(startpunkt, richtung, spleisswahrsch, laenge, dicke, geolaenge, bias);
		wackelblitz.setLight(true, 7);
						
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
		
		// ------------------------------------------------------
		
		lastTimerTick = fpsTimer.getTime();
		double lastFpsUpdate = lastTimerTick;
		int fps = 0;
		
		while (!Display.isCloseRequested()) {
			Timer.tick();
			// delta = fpsTimer.getTime() - lastTimerTick;
			lastTimerTick = fpsTimer.getTime();
			
			if (fpsTimer.getTime() - lastFpsUpdate > 1) {
				Display.setTitle(String.format(title + " (%d fps)", fps));
				lastFpsUpdate++;
				fps = 0;
			}
			fps++;
			if (Mouse.isButtonDown(0) && maxFlashes<7)
			{
				int ix=Mouse.getX()-400;
				int iy=Mouse.getY()-300;
				double dx = (double)ix/400d; 
				double dy = (double)iy/300d;
				richtung[0] = -dx;
				richtung[1] = dy;
				richtung[2] = -1-(1/(maxFlashes+1));
				bli[maxFlashes]=new Blitz(4096);
				bli[maxFlashes].sphereradius=sphererad;
				bli[maxFlashes].preset(startpunkt, richtung.clone(), spleisswahrsch, laenge, dicke, geolaenge, bias);
				bli[maxFlashes].setLight(true, maxFlashes);
				maxFlashes++;
			}
			
			renderGL();
			Display.update();
			Display.sync(60); // cap fps to 60fps
		}
		Display.destroy();
	}
	
	public static void renderGL() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
				
		// draw sphere
		GL11.glPushMatrix();
			GL11.glTranslated(0,0,depth/2);
			GL11.glBegin(GL11.GL_QUADS);
				GL11.glColor3d((1.0*70/255), (1.0*50/255), (1.0*45/255)); // Java ist echt scheiße
				sphere(sphererad,3,3);
			GL11.glEnd();
		GL11.glPopMatrix();
		
		for(int i=0;i<maxFlashes;i++)
		{
			if (Math.random() < 0.9) bli[i].regenerate();
			bli[i].draw(1,false);
		}
		wackelblitz.draw(1,false);
	}
	
	private static void initializeLighting() {
		// let there be light!
		GL11.glEnable(GL11.GL_LIGHTING);
		//GL11.glEnable(GL11.GL_LIGHT0);
		
		GL11.glEnable(GL11.GL_COLOR_MATERIAL);
		GL11.glColorMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT_AND_DIFFUSE);
		
		// materials
		FloatBuffer matSpecular = BufferUtils.createFloatBuffer(4);
		matSpecular.put(1.0f).put(1.0f).put(1.0f).put(1.0f).flip();
		
		GL11.glShadeModel(GL11.GL_SMOOTH);
		GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, matSpecular);
		GL11.glMaterialf(GL11.GL_FRONT, GL11.GL_SHININESS, 50.0f);
		
		// lights
		/*FloatBuffer lightPos = BufferUtils.createFloatBuffer(4);
		lightPos.put(1.0f).put(1.0f).put(8.0f).put(1.0f).flip();	// 0, 0, 7, 1; 1, 1, 1, 0
		GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, lightPos);
		/*******************************************************************
		FloatBuffer whiteLight = BufferUtils.createFloatBuffer(4);
		whiteLight.put(1.0f).put(1.0f).put(1.0f).put(1.0f).flip();
		GL11.glLight(GL11.GL_LIGHT0, GL11.GL_SPECULAR, whiteLight);	// sets specular light to white
		GL11.glLight(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, whiteLight);	// sets diffuse light to white
		
		
		FloatBuffer lModelAmbient = BufferUtils.createFloatBuffer(4);
		lModelAmbient.put(0.5f).put(0.5f).put(0.5f).put(1.0f).flip();
		GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, lModelAmbient);
		********************************************************************/
		
	}
	
	private static double degToRad = 2*Math.PI/180;
	public static void sphere(double radius, double dtheta, double dphi) {
		double x = 0, y = 0, z = 0;

		for (double theta = -90; theta <= 90 - dtheta; theta += dtheta) {
			for (double phi = 0; phi <= 360 - dphi; phi += dphi) {
				x = radius * Math.cos(theta*degToRad) * Math.cos(phi*degToRad);
				y = radius * Math.cos(theta*degToRad) * Math.sin(phi*degToRad);
				z = radius * Math.sin(theta*degToRad);
				if (Math.random() < 0.0002)
				{
					double startpunkt[] = {0,0,5};
					double richtung[] = {x,y,z};
					double spleisswahrsch =0.72;
					int laenge = 25;
					double dicke = 0.030;
					double geolaenge =0.3;
					wackelblitz.preset(startpunkt, richtung, spleisswahrsch, laenge, dicke, geolaenge, bias);
					wackelblitz.regenerate();
				}
				GL11.glVertex3d(x, y, z);
				
			    GL11.glVertex3d(radius * Math.cos((theta+dtheta)*degToRad) * Math.cos(phi*degToRad),
						radius * Math.cos((theta+dtheta)*degToRad) * Math.sin(phi*degToRad),
						radius * Math.sin((theta+dtheta)*degToRad));

				GL11.glVertex3d(radius * Math.cos((theta+dtheta)*degToRad) * Math.cos((phi+dphi)*degToRad),
						radius * Math.cos((theta+dtheta)*degToRad) * Math.sin((phi+dphi)*degToRad),
						radius * Math.sin((theta+dtheta)*degToRad));
     
				if (theta > -90 && theta < 90) {
					GL11.glVertex3d(radius * Math.cos(theta*degToRad) * Math.cos((phi+dphi)*degToRad),
							radius * Math.cos(theta*degToRad) * Math.sin((phi+dphi)*degToRad),
							radius * Math.sin(theta*degToRad));
				}
			}
		}
	}
	
	/*public static void circle(double radius, double stepCount) {
		GL11.glColor3d(1,1,1);
		GL11.glVertex3d(0,0,0);	// origin
		
		GL11.glColor3d(0,1,0);
		
		double angle;
		for (int step = 0; step < stepCount; step++) {
			angle = 2.0*Math.PI * step/stepCount;
			GL11.glColor3d(Math.cos(angle), Math.sin(angle), 1);
			GL11.glVertex3d(radius * Math.cos(angle), radius * Math.sin(angle), 0);
		}
		GL11.glVertex3d(radius, 0, 0);	// close the circle
	}*/
}